package com.gamelife.spring;

import com.gamelife.spring.annotation.Autowired;
import com.gamelife.spring.annotation.Component;
import com.gamelife.spring.annotation.ComponentScan;
import com.gamelife.spring.annotation.Scope;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class AnnotationConfigApplicationContext {
    // 单例池
    private ConcurrentHashMap<String,Object> singletonObjects = new ConcurrentHashMap<>();

    private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    // 后置处理器列表
    private List<BeanPostProcessor> beanPostProcessorList= new ArrayList<>();

    public AnnotationConfigApplicationContext(Class configClass) {

        scan(configClass);

        // 循环beanDefinitionMap，创建单例bean
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();
            // 判断Scope是否为singleton类型
            if ("singleton".equals(beanDefinition.getScope())) {
                singletonObjects.put(beanName,createBean(beanName,beanDefinition));
            }
        }
    }

    /**
     * 扫描配置类路径下的所有注入类的信息
     * @param configClass
     */
    private void scan(Class configClass) {
        // 获取配置类上面的componentScan注解
        ComponentScan componentScan = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
        String scanPath = componentScan.value();  //com.gamelife.test.service

        // 对路径下的文件进行扫描、加载
        ClassLoader classLoader = AnnotationConfigApplicationContext.class.getClassLoader();
        String newScanPath = scanPath.replace(".","/");
        URL resource = classLoader.getResource(newScanPath);

        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            for (File fileItem : file.listFiles()) {
                // 截取类的全包名
                String absolutePath = fileItem.getAbsolutePath();
                String className = absolutePath.substring(absolutePath.indexOf("classes/") + 8, absolutePath.indexOf(".class"));
                className = className.replace("/",".");

                // 加载这些扫描到的类
                try {
                    Class<?> loadClass = classLoader.loadClass(className);
                    // 判断此类有没有Component注解
                    if(loadClass.isAnnotationPresent(Component.class)){
                        Component component = loadClass.getAnnotation(Component.class);

                        // 创建BeanDefinition 并保存到beanDefinitionMap中
                        BeanDefinition beanDefinition = new BeanDefinition();

                        // beanName的获取
                        String beanName = getComponentValue(component,loadClass);

                        // bean的clazz类型
                        beanDefinition.setClazz(loadClass);

                        // 读取Scope注解，判断是singleton还是prototype
                        if (loadClass.isAnnotationPresent(Scope.class)) {
                            Scope scope = loadClass.getAnnotation(Scope.class);
                            beanDefinition.setScope(scope.value());
                        }else{
                            beanDefinition.setScope("singleton");
                        }

                        beanDefinitionMap.put(beanName,beanDefinition);


                        // 判断bean是否实现了BeanPostProcessor
                        if (BeanPostProcessor.class.isAssignableFrom(loadClass)) {
                            BeanPostProcessor beanPostProcessor = null;
                            try {
                                beanPostProcessor = (BeanPostProcessor) loadClass.getDeclaredConstructor().newInstance();
                            } catch (InstantiationException e) {
                                e.printStackTrace();
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            } catch (NoSuchMethodException e) {
                                e.printStackTrace();
                            }
                            beanPostProcessorList.add(beanPostProcessor);
                        }
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public Object createBean(String beanName, BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getClazz();
        Object obj = null;
        try {
            obj = clazz.getDeclaredConstructor().newInstance();
            // ioc 依赖注入
            for (Field field : clazz.getDeclaredFields()) {
                if(field.isAnnotationPresent(Autowired.class)){
                    // 获取字段的beanName
                    ClassLoader classLoader = AnnotationConfigApplicationContext.class.getClassLoader();
                    try {
                        // 获取字段的class对象
                        Class<?> loadClass = classLoader.loadClass(field.getType().getCanonicalName());
                        if (loadClass.isAnnotationPresent(Component.class)) {
                            String filedBeanName = getComponentValue(loadClass.getDeclaredAnnotation(Component.class),loadClass);
                            Object bean = getBean(filedBeanName);
                            field.setAccessible(true);
                            field.set(obj,bean);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }

            // Aware回掉 传入beanName
            if(obj instanceof BeanNameAware){
                ((BeanNameAware) obj).setBeanName(beanName);
            }


            // before
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                obj = beanPostProcessor.postProcessBeforeInitialization(obj, beanName);
            }

            // 实现InitializingBean的afterPropertiesSet方法进行初始化
            if(obj instanceof InitializingBean){
                try {
                    ((InitializingBean) obj).afterPropertiesSet();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            // after
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                obj = beanPostProcessor.postProcessAfterInitialization(obj, beanName);
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return obj;
    }



    public Object getBean(String beanName){
        // 判断beanDefinitionMap中是否存在
        if (beanDefinitionMap.containsKey(beanName)) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            // 判断scope类型
            if("singleton".equals(beanDefinition.getScope())){
                return singletonObjects.get(beanName);
            }else{
                return createBean(beanName,beanDefinition);
            }
        }else {
            throw new NullPointerException();
        }
    }

    /**
     * 获取component的值，value==""时将类名首字母小写作为beanName
     * @param component
     * @param loadClass
     * @return
     */
    public String getComponentValue(Component component,Class loadClass){
        String beanName = component.value();
        if("".equals(beanName)){
            // UserService -> userService
            beanName = loadClass.getSimpleName().substring(0,1).toLowerCase(Locale.ROOT) +loadClass.getSimpleName().substring(1);
        }
        return beanName;
    }


}
